/*
 * TuplesProcessing.cpp
 *
 *  Created on: 31/01/2014
 *      Author: root
 */

#include "TuplesProcessing.h"

using namespace std;

//sacar a archivo de configuraciones
#define CHECK_IDLE_COND_WAIT_TIME_SECONDS 1 //???
#define MAX_TUPLE_LENGTH_TO_SHARE 3


extern int rank;
extern DppmParams * dppm;
extern Tuple * bestSolution;
extern bool end;
extern SortedBuffer * tuples;
extern pthread_mutex_t best_solution_mutex;
extern pthread_mutex_t tuples_mutex;
extern pthread_mutex_t end_flag_mutex;
extern pthread_cond_t idle_cond;

void EvalSolution(Tuple * newSol){

	pthread_mutex_lock(&best_solution_mutex);

	if(!bestSolution->empty()){
	//	cout<<"optimalSolution(old,new): ( "<<oldSol->cost()<<" , " <<newSol->cost()<<" )"<<endl;
	}

	if (!bestSolution->empty() && ( bestSolution->cost() <= newSol->cost() )){
		delete newSol;
	}else{
		delete bestSolution;
		bestSolution = newSol;
	}

	pthread_mutex_unlock(&best_solution_mutex);
}

//esta funcion aplica la poda
bool canBeOpt(Tuple * cand){

	pthread_mutex_lock(&best_solution_mutex);
	Tuple bestSolCopy = *(bestSolution->copy());
	pthread_mutex_unlock(&best_solution_mutex);

	if (bestSolCopy.empty()){
		return true;
	}


	int timeMin = cand->times(cand->lastAct());
	int time = 0;
	int timeMode = 0;

	int costMin = cand->cost();
	int cost = 0;
	int costMode = 0;
	int * times = NULL;
	int * costs = NULL;

	for(int i = cand->lastAct(); i < dppm->getNumActivities(); i++){
		//obtengo el tiempo minimo posible para el resto de las activades sin asignar
		// y me fijo si se pasa del deadline
		for(int j = 0; j < dppm->getActivityNumModes(i); j++){
			times = dppm->getActivityModesTimes(i);
			costs = dppm->getActivityModesCosts(i);
			timeMode = times[j];
			costMode = costs[j];
			time = ((time == 0)||(time <= timeMode)) ? time : timeMode;
			cost = ((cost == 0)||(cost <= costMode)) ? cost : costMode;

		}
		timeMin += time;
		costMin += cost;
		if ((timeMin > dppm->getDeadline())||(!bestSolCopy.empty() && (bestSolCopy.cost() <= costMin)))
			return false;

	}

	return (bestSolCopy.cost() > costMin);
}



void ProcessTupleStep(Tuple * T){


	//int countActs = GetNumActivities(dppmParms);
	int numModes = dppm->getActivityNumModes(T->lastAct() + 1);
	Tuple * T2;
	for(int i = 0 ; i < numModes; i++){
		T2 = T->copy();
		T2->sigAct();
		T2->modes(T2->lastAct(),i);
		//calculo el tiempo y el costo que insume la nueva tupla
		//obtiene el tiempo maximo que demoran sus predecesores

		int time = dppm->getPredsMaxTime(T2);
		//obtengo el tiempo que insume la actividad T2->now en el modo i y se lo sumo
		int timeMode = (dppm->getActivityModesTimes(T2->lastAct()))[i];
		time += timeMode;
		//el tiempo de la tupla es el ma
		T2->times(T2->lastAct(),time);
		T2->time( (T2->time() <= time) ? time : T2->time() );

		//sumo el costo del modo de la nueva actividad

		T2->cost( T2->cost() + dppm->getActivityModesCosts(T2->lastAct())[i] );

		if( T2->isSolution() && T2->time() <= dppm->getDeadline()){
			//Compara T2 con bestSolution y en caso de que sea mejor actualiza bestSolution
			EvalSolution(T2);
		}else{
			if((T2->times(T2->lastAct()) <= dppm->getDeadline()) && canBeOpt(T2)){
				tuples->push(T2);
			}else{
				delete T2;
			}
		}
	}//for
	delete T;
}



int TuplesProcessing(){

	//MPI_Comm_rank(MPI_COMM_WORLD, &rank);
	cout<<"Comanzando TuplesProcessing, rank = "<<rank<<endl;
	bool exitCondition;
	queue<Tuple*> AlmostFinished;
	Tuple * tuple = NULL;

	do{

		if( AlmostFinished.empty() ){

			pthread_mutex_lock(&tuples_mutex);

			//Si tengo un prefijo para procesar
			if((tuple = tuples->pop()) != NULL){

				ProcessTupleStep(tuple);

			}else{

				struct timespec ts;
				ts.tv_sec = time(NULL) + CHECK_IDLE_COND_WAIT_TIME_SECONDS;

				do{

					pthread_mutex_lock(&end_flag_mutex);
					exitCondition = end;
					pthread_mutex_unlock(&end_flag_mutex);

				}while(!exitCondition &&
						pthread_cond_timedwait(&idle_cond,&tuples_mutex,&ts) == ETIMEDOUT);

			}

			pthread_mutex_unlock(&tuples_mutex);

		}else{

			tuple = AlmostFinished.front();
			AlmostFinished.pop();
			ProcessTupleStep(tuple);
		}

	}while(!exitCondition);

	return 0;

}



